#pragma once
#include "platform.hpp"
#include "stdlib/bugcheck.hpp"
#include "stdlib/exception.hpp"
using namespace JHCPP::stdlib;
using namespace JHCPP::stdlib::jhException;


#if defined(JH_OS_WINDOWS)
#include <Windows.h>
#elif defined(JH_OS_LINUX)
#include <pthread.h>
#include <errno.h>
#endif

namespace JHCPP
{
	namespace event
	{
		class CScopedRWLock;
		class CScopedReadRWLock;
		class CScopedWriteRWLock;

	#if defined(JH_OS_WINDOWS)
		class CRWLockImpl
		{
		protected:
			CRWLockImpl();
			~CRWLockImpl();
			void readLockImpl();
			bool tryReadLockImpl();
			void writeLockImpl();
			bool tryWriteLockImpl();
			void unlockImpl();

		private:
			void addWriter();
			void removeWriter();
			DWORD tryReadLockOnce();

			HANDLE   m_mutex;
			HANDLE   m_readEvent;
			HANDLE   m_writeEvent;
			unsigned m_readers;
			unsigned m_writersWaiting;
			unsigned m_writers;
		};
	#elif defined(JH_OS_LINUX)
		class CRWLockImpl
		{
		protected:
			CRWLockImpl();
			~CRWLockImpl();
			void readLockImpl();
			bool tryReadLockImpl();
			void writeLockImpl();
			bool tryWriteLockImpl();
			void unlockImpl();

		private:
			pthread_rwlock_t m_rwl;
		};
	#endif

		class CRWLock: private CRWLockImpl
		{
		public:
			typedef CScopedRWLock ScopedLock;
			typedef CScopedReadRWLock ScopedReadLock;
			typedef CScopedWriteRWLock ScopedWriteLock;

			CRWLock()
			{

			}

			~CRWLock()
			{

			}

			void readLock()
			{
				readLockImpl();
			}

			bool tryReadLock()
			{
				return tryReadLockImpl();
			}

			void writeLock()
			{
				writeLockImpl();
			}

			bool tryWriteLock()
			{
				return tryWriteLockImpl();
			}

			void unlock()
			{
				unlockImpl();
			}

		private:
			CRWLock(const CRWLock&);
			CRWLock& operator = (const CRWLock&);
		};


		class CScopedRWLock
		{
		public:
			CScopedRWLock(CRWLock& rwl, bool write = false)
			: m_rwl(rwl)
			{
				if (write)
					m_rwl.writeLock();
				else
					m_rwl.readLock();
			}

			~CScopedRWLock()
			{
				try
				{
					m_rwl.unlock();
				}
				catch (...)
				{
					jh_unexpected();
				}
			}

		private:
			CRWLock& m_rwl;

			CScopedRWLock();
			CScopedRWLock(const CScopedRWLock&);
			CScopedRWLock& operator = (const CScopedRWLock&);
		};

		class CScopedReadRWLock : public CScopedRWLock
		{
		public:
			CScopedReadRWLock(CRWLock& rwl)
			: CScopedRWLock(rwl, false)
			{

			}

			~CScopedReadRWLock()
			{

			}
		};

		class CScopedWriteRWLock : public CScopedRWLock
		{
		public:
			CScopedWriteRWLock(CRWLock& rwl)
			: CScopedRWLock(rwl, true)
			{

			}

			~CScopedWriteRWLock()
			{

			}
		};
	}//end of namespace event
}//end of namespace JHCPP
